﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using PersistenciaAccessLIB;
using System.Configuration;
using System.Collections;

namespace KimberlyDashboardLIB
{
    public class Dashboard
    {
        private Persistencia _persistencia;

        public Dashboard()
        {
            this._persistencia = new Persistencia(ConfigurationManager.ConnectionStrings["CONEXION"].ToString());
        }

        #region "Métodos publicos"
        

        /// <summary>
        /// Retorna datast con listado de perspectivas
        /// </summary>
        /// <returns></returns>
        public DataSet GetPerspectivas()
        {
            return this._persistencia.ExecuteDataSet("SELECT Id, Perspectiva FROM PERSPECTIVA ORDER BY Perspectiva");
        }

        /// <summary>
        /// retorna arreglo de string con nombres de los graficos
        /// </summary>
        /// <returns></returns>
        public string[] GetGraficos()
        {
            return Enum.GetNames(typeof(Enumeraciones.Grafico));            
        }

        /// <summary>
        /// retorna arreglo de string con nombres de las unidades de medida
        /// </summary>
        /// <returns></returns>
        public string[] GetUnidadesMedida()
        {
            return Enum.GetNames(typeof(Enumeraciones.UnidadMedida));
        }

        /// <summary>
        /// ValorInventario
        /// </summary>
        /// <param name="idIndicador">0 si se quieren obtener todos los indicadores</param>        
        /// <returns></returns>
        public DataSet GetIndicadores(int idIndicador)
        {
            string sql = "SELECT INDICADOR.Id, IdPerspectiva, Perspectiva, Nombre, Graficodefecto, UnidadMedida FROM INDICADOR " +
                "INNER JOIN PERSPECTIVA ON INDICADOR.Idperspectiva = PERSPECTIVA.Id " +                
                "WHERE INDICADOR.Activo = 1 ";

            if (idIndicador > 0)
                sql += " AND INDICADOR.id = " + idIndicador.ToString();            

            sql += " ORDER BY Perspectiva";
            return this._persistencia.ExecuteDataSet(sql);
        }

        /// <summary>
        /// Sube la informacion del archivo excel que le llega a una base de datos
        /// </summary>
        /// <param name="pathArchivo"></param>
        public void SubirInformacion(string pathArchivo, int ano)
        {
            DataSet dts = Utilidades.LeerExcel(pathArchivo);

            if (dts.Tables.Count == 0)
                throw new Exception("No se encontraron tablas en el archivo excel");

            //Se eliminan las dos primeras columnas y las 3 primeras filas, que no interesan
            dts.Tables[0].Columns.RemoveAt(1);
            dts.Tables[0].Columns.RemoveAt(0);
            dts.Tables[0].Rows.RemoveAt(2);
            dts.Tables[0].Rows.RemoveAt(1);
            dts.Tables[0].Rows.RemoveAt(0);
            dts.Tables[0].AcceptChanges();

            //Se obtienen los indicadores
            DataSet dtsIndicadores = this.GetIndicadores(0);

            //Recorre los registros del excel y va guardando los valores
            int idIndicador = 0;
            for (int i = 0; i < dts.Tables[0].Rows.Count; i++)
            { 
                //Lo que se lee en la primera columna es el nombre del indicador, se obtiene el id correspondiente
                //y se guardan los valores. Si la primera columna esta vacía se trata de los 
                //sub-indicadores (los que no estan en negrilla en el excel), por lo que no se hace nada con esta información
                if (dts.Tables[0].Rows[i][0].ToString().Trim().Length > 0)
                {
                    idIndicador = this.GetIndicadorByTexto(dts.Tables[0].Rows[i][0].ToString(), dtsIndicadores.Tables[0]);
                    if(idIndicador > 0)
                        this.GuardarValores(dts.Tables[0].Rows[i], idIndicador, ano);
                }
            }            
        }

        #endregion

        #region "Metodos privados"

        /// <summary>
        /// Guarda los valores del indicador que le llega. Si un valor de los que llega ya se encuentra, se actualiza,
        /// de los contrario se inserta. Para que este método funcione correctamente se necesita que los indices de las
        /// columnas no cambien
        /// </summary>
        /// <param name="dr"></param>
        /// <param name="idIndicador"></param>
        /// <param name="ano"></param>
        private void GuardarValores(DataRow dr, int idIndicador, int ano)
        { 
            //Las columnas estan en este orden (por trimestres): mes,mes,mes,ytdQ,metaq,mes,mes,mes,YTDQ,MetaQ,....etc.
            //Se construyen Hashtables con el indice(key) y numero(value) correspondiente para: meses, Q's y Metas
            Hashtable hashMes = new Hashtable();
            Hashtable hashQ = new Hashtable();
            Hashtable hashMeta = new Hashtable();

            hashMes.Add(9, 1);      //En la columna 9 se encuentra el mes 1
            hashMes.Add(10, 2);
            hashMes.Add(11, 3);
            hashMes.Add(14, 4);
            hashMes.Add(15, 5);
            hashMes.Add(16, 6);
            hashMes.Add(19, 7);
            hashMes.Add(20, 8);
            hashMes.Add(21, 9);
            hashMes.Add(24, 10);
            hashMes.Add(25, 11);
            hashMes.Add(26, 12);

            hashQ.Add(12, 1);
            hashQ.Add(17, 2);
            hashQ.Add(22, 3);
            hashQ.Add(27, 4);

            hashMeta.Add(13, 1);
            hashMeta.Add(18, 2);
            hashMeta.Add(23, 3);
            hashMeta.Add(28, 4);

            //Se recorren los meses
            int columna = 0;
            int mes = 0;                   
            foreach (DictionaryEntry item in hashMes)
            {
                columna = Convert.ToInt32(item.Key.ToString());
                mes = Convert.ToInt32(item.Value.ToString());
                this.ActualizarValor(Enumeraciones.Valores.VALORMES, idIndicador, mes, ano, dr[columna].ToString());
            }

            //Se recorren los Q            
            int contadorQ = 0;
            foreach (DictionaryEntry item in hashQ)
            {
                columna = Convert.ToInt32(item.Key.ToString());
                contadorQ = Convert.ToInt32(item.Value.ToString());
                this.ActualizarValor(Enumeraciones.Valores.VALORQ, idIndicador, contadorQ, ano, dr[columna].ToString());
            }

            //Se recorren las metas           
            int contadorMeta = 0;
            foreach (DictionaryEntry item in hashMeta)
            {
                columna = Convert.ToInt32(item.Key.ToString());
                contadorMeta = Convert.ToInt32(item.Value.ToString());
                this.ActualizarValor(Enumeraciones.Valores.VALORMETA, idIndicador, contadorMeta, ano, dr[columna].ToString());
            }
        }


        /// <summary>
        /// Actualiza la informacion de loa valores de mes, Q y metas, para el indicador que le llega
        /// </summary>
        /// <param name="tabla"></param>
        /// <param name="idIndicador"></param>
        /// <param name="contador">Numero de mes o Q del año</param>
        /// <param name="ano"></param>
        /// <param name="valor">Valor a actualizar. Puede ser un vacío, en tal caso se elimina de la tabla</param>
        private void ActualizarValor(Enumeraciones.Valores tabla, int idIndicador, int contador, int ano, string valor)
        {
            string nombreTabla = this.GetNombreTabla(tabla);
            string columnaContador = this.GetNombreColumna(tabla);
            string sql = "";

            //Si el valor es vacío se elimina el registro de la tabla
            if (valor.Trim().Length == 0)
            {
                sql = "DELETE FROM " + nombreTabla + " WHERE IdIndicador = " + idIndicador.ToString() + " AND " +
                    "Ano = " + ano.ToString() + " AND " + columnaContador + " = " + contador.ToString();
            }
            else
            {
                //Se determina si ya existe valor. Si no existe se inserta, si existe se actualiza
                sql = "SELECT * FROM " + nombreTabla + " WHERE IdIndicador = " + idIndicador.ToString() + " AND " +
                    "Ano = " + ano.ToString() + " AND " + columnaContador + " = " + contador.ToString();
                DataSet dts = this._persistencia.ExecuteDataSet(sql);

                //Cambia comas por puntos en el valor
                valor = valor.Replace(",", ".");

                //Se inserta o actualiza segun sea el caso
                if (dts.Tables[0].Rows.Count == 0)
                {
                    sql = "INSERT INTO " + nombreTabla + " (IdIndicador, Ano, " + columnaContador + ", Valor)" +
                        "VALUES (" + idIndicador.ToString() + ", " + ano.ToString() + ", " + contador.ToString() + ", " + valor + ")";
                }
                else
                {
                    sql = "UPDATE " + nombreTabla + " SET Valor = " + valor + " WHERE IdIndicador = " + idIndicador.ToString() + " AND " +
                    "Ano = " + ano.ToString() + " AND " + columnaContador + " = " + contador.ToString();
                }
            }

            //Se ejecuta la consulta
            this._persistencia.ExecuteNonQuery(sql);
        }

        /// <summary>
        /// Encuentra el id del indicador por nombre
        /// </summary>
        /// <param name="texto">Texto con el nombre del indicador que se va a buscar</param>
        /// <param name="dt">Datatable con la informacion de los indicadores</param>
        /// <returns></returns>
        private int GetIndicadorByTexto(string texto, DataTable dt)
        {
            int retorno = 0;
            //Se eliminan simbolos y tildes
            texto = this.EliminarCaracteres(texto);

            //Recorre la tabla y va buscando coincidencia con el texto
            string nombreColumna = "";
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                nombreColumna = this.EliminarCaracteres(dt.Rows[i]["Nombre"].ToString());
                if (nombreColumna.Equals(texto))
                {
                    retorno = Convert.ToInt32(dt.Rows[i]["Id"].ToString());
                    break;
                }                    
            }

            return retorno;            
        }

        /// <summary>
        /// Elimina simbolos y tildes del texto que le llega como parametro
        /// </summary>
        /// <param name="texto"></param>
        /// <returns></returns>
        private string EliminarCaracteres(string texto)
        {
            texto = texto.Replace("%", "");
            texto = texto.Replace("$", "");
            texto = texto.Replace("#", "");
            texto = texto.Replace("á", "a");
            texto = texto.Replace("é", "e");
            texto = texto.Replace("í", "i");
            texto = texto.Replace("ó", "o");
            texto = texto.Replace("ú", "u");
            texto = texto.Replace("Á", "A");
            texto = texto.Replace("É", "E");
            texto = texto.Replace("Í", "I");
            texto = texto.Replace("Ó", "O");
            texto = texto.Replace("Ú", "U");
            texto = texto.Replace("  ", " ");
            texto = texto.Trim();
            texto = texto.ToLower();

            return texto;
        }

        /// <summary>
        /// Retorna el nombre de la tabla asociado al valor de la enumeracion que recibe
        /// </summary>
        /// <param name="tabla"></param>
        /// <returns></returns>
        private string GetNombreTabla(Enumeraciones.Valores tabla)
        {
            string retorno = "";
            switch (tabla)
            {
                case Enumeraciones.Valores.VALORMES:
                    retorno = "VALOR_MES";                    
                    break;
                case Enumeraciones.Valores.VALORQ:
                    retorno = "VALOR_Q";                    
                    break;
                case Enumeraciones.Valores.VALORMETA:
                    retorno = "META_Q";                    
                    break;
            }
            return retorno;
        }

        /// <summary>
        /// Retorna el nombre de la columna asociado al valor de la enumeracion que recibe
        /// </summary>
        /// <param name="tabla"></param>
        /// <returns></returns>
        private string GetNombreColumna(Enumeraciones.Valores tabla)
        {
            string retorno = "";
            switch (tabla)
            {
                case Enumeraciones.Valores.VALORMES:                    
                    retorno = "Mes";
                    break;
                case Enumeraciones.Valores.VALORQ:                    
                    retorno = "Q";
                    break;
                case Enumeraciones.Valores.VALORMETA:                    
                    retorno = "Q";
                    break;
            }
            return retorno;
        }

        #endregion

        #region "Obtener valores"

        /// <summary>
        /// Retorna los valores almacenados en la base de datos y que cumplen con lo criterios que le llegan
        /// Se puede consultar solamente un indicador (o todos)
        /// </summary>
        /// <param name="tabla"></param>
        /// <param name="anoInicial"></param>
        /// <param name="anoFinal"></param>
        /// <param name="mesInicial"></param>
        /// <param name="mesFinal"></param>
        /// <param name="idIndicador">Si llega 0 se retornan todos los indicadores</param>
        /// <returns></returns>
        public DataSet GetValores(Enumeraciones.Valores tabla, int anoInicial, int anoFinal, int mesInicial, int mesFinal, int idIndicador)
        {
            string nombreTabla = this.GetNombreTabla(tabla);
            string nombreColumna = this.GetNombreColumna(tabla);

            string sql = "SELECT INDICADOR.Nombre, IdIndicador, Ano, " + nombreColumna + ", Valor FROM " + nombreTabla + " " +
                "INNER JOIN INDICADOR ON " + nombreTabla + ".IdIndicador = INDICADOR.Id " +
                "WHERE (Ano >= " + anoInicial.ToString() + " AND " + nombreColumna + " >= " + mesInicial + ") " +
                "AND (Ano <= " + anoFinal.ToString() + " AND " + nombreColumna + " <= " + mesFinal + ") " +
                "AND INDICADOR.Activo = 1 ";

            if (idIndicador > 0)
                sql = sql + "AND IdIndicador = " + idIndicador.ToString() + " ";

            sql = sql + "ORDER BY IdIndicador, Ano, " + nombreColumna;

            return this._persistencia.ExecuteDataSet(sql);
        }

        /// <summary>
        /// Retorna los valores almacenados en la base de datos y que cumplen con lo criterios que le llegan
        /// Se pueden consultar varios indicadores
        /// </summary>
        /// <param name="tabla"></param>
        /// <param name="anoInicial"></param>
        /// <param name="anoFinal"></param>
        /// <param name="mesInicial"></param>
        /// <param name="mesFinal"></param>
        /// <param name="idIndicador">Ids de los indicadores que se van a consultar, separados por comas</param>
        /// <returns></returns>
        public DataSet GetValores(Enumeraciones.Valores tabla, int anoInicial, int anoFinal, int mesInicial, int mesFinal, string idIndicador)
        {
            string nombreTabla = this.GetNombreTabla(tabla);
            string nombreColumna = this.GetNombreColumna(tabla);

            string sql = "SELECT INDICADOR.Nombre, IdIndicador, Ano, " + nombreColumna + ", Valor FROM " + nombreTabla + " " +
                "INNER JOIN INDICADOR ON " + nombreTabla + ".IdIndicador = INDICADOR.Id " +
                "WHERE (Ano >= " + anoInicial.ToString() + " AND " + nombreColumna + " >= " + mesInicial + ") " +
                "AND (Ano <= " + anoFinal.ToString() + " AND " + nombreColumna + " <= " + mesFinal + ") " +
                "AND INDICADOR.Activo = 1 ";

            if (idIndicador.Length > 0)
                sql = sql + "AND IdIndicador IN (" + idIndicador + ") ";

            sql = sql + "ORDER BY IdIndicador, Ano, " + nombreColumna;

            return this._persistencia.ExecuteDataSet(sql);
        }

        /// <summary>
        /// Retorna todos los valores almacenados en la base de datos, para todos los indicadores, años y meses (o q's)
        /// </summary>
        /// <param name="tabla"></param>
        /// <returns></returns>
        public DataSet GetValores(Enumeraciones.Valores tabla)
        {
            string nombreTabla = this.GetNombreTabla(tabla);
            string nombreColumna = this.GetNombreColumna(tabla);
            
            string sql = "SELECT INDICADOR.Nombre, IdIndicador, Ano, " + nombreColumna + ", Valor FROM " + nombreTabla + " " +
                "INNER JOIN INDICADOR ON " + nombreTabla + ".IdIndicador = INDICADOR.Id " +
                "WHERE INDICADOR.Activo = 1 ORDER BY Ano, " + nombreColumna;

            return this._persistencia.ExecuteDataSet(sql);
        }

        #endregion

    }    

}
